package com.cpjit.data;

import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
 * 扫描jakarta.validation注解在保存时对实体字段进行基本的校验，如非空、大于0.
 *
 * @author yonghuan[cpjit@qq.com]
 * @see jakarta.validation.constraints
 */
@AllArgsConstructor
@Slf4j
public class ValidationInterceptor implements InnerInterceptor {

    private final Validator validator;

    @Override
    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
        // 取到实体类
        Object entity = null;
        if (parameter instanceof Map<?, ?> map) {
            if (map.containsKey(Constants.ENTITY)) {
                entity = map.get(Constants.ENTITY);
            }
        } else {
            entity = parameter;
        }
        try {
            doValidate(entity, ms);
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new IllegalArgumentException("校验失败", e);
        }
    }

    private void doValidate(Object entity, MappedStatement ms) throws ClassNotFoundException, NoSuchMethodException {
        if (entity != null) {
            final Set<ConstraintViolation<Object>> constraintViolations = validator.validate(entity);
            if (!constraintViolations.isEmpty()) {
                ConstraintViolation<?> constraintViolation = constraintViolations.iterator().next();
                String propertyName = constraintViolation.getPropertyPath().toString();
                log.warn("校验不通过: {}#{} {}", entity.getClass().getName(), propertyName, constraintViolation.getMessage());
//                final Field field = ReflectionUtils.findField(entity.getClass(), propertyName);
//                if (field != null) {
//                    final ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
//                    if (apiModelProperty != null) {
//                        propertyName = String.format("%s(%s)", propertyName, apiModelProperty.value());
//                    }
//                }
                throw new ConstraintViolationException(String.format("%s %s", propertyName, constraintViolation.getMessage())
                        , Collections.singleton(constraintViolation));
            }
        }
    }
}
